/***************************************************************************
 *   Copyright (C) 2009 by Damian Kmiecik                                  *
 *   d0zoenator@gmail.com                                                  *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 *                                                                         *
 ***************************************************************************/

/**
 * SPI software/hardware implementation
 *
 * @author 	Damian Kmiecik
 * @processor 	AVR
 * @package 	spi
 * @compiler 	avr-gcc
 */

#include <avr/io.h>
#include "main.h"
#include "spi.h"

/**
 * SPI initialize
 * Must be run before any usage of spi functions
 */
void spiInit(void) {
	// Configure I/O registers
	SPI_DDR |= _BV(SPI_MOSI) | _BV(SPI_SCK);
	SCK_SET;
#ifdef SPI_READ
	SPI_DDR &= ~_BV(SPI_MISO);
//	SPI_DDR |= _BV(SPI_SS);
#endif
#ifndef SPI_SOFTWARE
	SPCR = _BV(SPE) | _BV(MSTR);
	SPSR = _BV(SPI2X);
#endif
}

/**
 * Write byte to SPI
 * @param uint8_t val
 */
void spiWrite(uint8_t val) {
#ifdef SPI_SOFTWARE
	// Loop, send bits one by one
	uint8_t i;
	for (i = 8; i; i--)
	{
		// Check bit and set 1/0
		if (val & 128)
			MOSI_SET;
		else
			MOSI_CLR;
		// Clock pulse
		SCK_SET;
		SCK_CLR;
		// Roll bits
		val <<= 1;
	}
#else
	SPDR = val;
	uint8_t back = 0xFF;
	while (!(SPSR & (1 << SPIF)) && back)
		back--;
#endif
}

#ifdef SPI_READ
/**
 * Read byte from SPI
 * @return uint8_t
 */
uint8_t spiRead(void) {
#ifdef SPI_SOFTWARE
	// Val and counter
	uint8_t val;
	val = 0;
	// Set miso
	MOSI_SET;
	// Loop, read bits one by one
	uint8_t i;
	for (i = 8; i; i--)
	{
		// Roll bits
		val <<= 1;
		// Clock
		SCK_SET;
		// When MISO sets, set bit in value
		if (MISO)
		val |= 1;
		// Clock
		SCK_CLR;
	}
	// Return value
	return val;
#else
	SPDR = 0x00;
	uint8_t back = 0xFF;
	while (!(SPSR & (1 << SPIF)) && back)
		back--;
	return SPDR;
#endif
}
#endif
